<html>
    <head>
        <title>光照初探</title>
        <link rel="stylesheet" type="text/css" href="lib/webgl-tutorials.css">
    </head>
    <body onload="main()">
        <canvas id = "c"></canvas>
        <div id="uiContainer">
            <div id="ui">
                <div id="cx"></div>
                <div id="angleY"></div>
            </div>
            </div>
    </body>
    <script type='text/javascript' src="lib/webgl-utils.js"></script>
    <script type='text/javascript' src="lib/webgl-lessons-ui.js"></script>
    <script type='text/javascript' src="lib/m4.js"></script>
    <script id="vertex-shader-2d" type="x-shaderx-shader/x-vertex">
        attribute vec4 a_Position;
        uniform mat4 u_WorldViewProjection;
        uniform mat4 u_World;
        //attribute vec4 a_Color;
        //varying vec4 v_Color;
        attribute vec3 a_Normal;
        varying vec3 v_Normal;

        void main(){
            gl_Position = u_WorldViewProjection * a_Position;
            //v_Color = a_Color;
            //重定法向传递片段着色器
            v_Normal =  mat3(u_World) * a_Normal;//
        }
    </script>
    <script id="fragment-shader-2d" type="x-shader/x-fragment">
        precision mediump float;
        //varying vec4 v_Color;
        uniform vec4 u_Color;
        varying vec3 v_Normal;
        uniform vec3 u_ReverseLightDirection;
        void main(){
            //gl_FragColor = v_Color;
            gl_FragColor = u_Color;
            vec3 normal = normalize(v_Normal);
            float light = dot(normal, u_ReverseLightDirection);//点乘
            gl_FragColor.rgb *= light;
        }
    </script>
    <script type="text/javascript">
        var fRotationRadians = 0;
        //var cameraTarget = [0, 35, 0];

        function main(){
            var canvas = document.getElementById("c");
            var gl = canvas.getContext("webgl");
            if(!gl){
                error("not supported webgl.");
                return; 
            }

            setupUI();

        
            //编译shader
            var program = webglUtils.createProgramFromScripts(gl, ["vertex-shader-2d", "fragment-shader-2d"]);
            var a_Position = gl.getAttribLocation(program, "a_Position");
            var u_WorldViewProjection = gl.getUniformLocation(program, "u_WorldViewProjection");
            var u_World = gl.getUniformLocation(program, "u_World");
            //var a_Color = gl.getAttribLocation(program, "a_Color");
            var u_Color = gl.getUniformLocation(program, "u_Color");
            var a_Normal = gl.getAttribLocation(program, "a_Normal");
            var u_ReverseLightDirection = gl.getUniformLocation(program, "u_ReverseLightDirection");

            //顶点buffer
            var vertexBuffer = gl.createBuffer();
            gl.bindBuffer(gl.ARRAY_BUFFER, vertexBuffer);
            //设置顶点属性
            setRectangle();

            var colorBuffer = gl.createBuffer();
            gl.bindBuffer(gl.ARRAY_BUFFER, colorBuffer);
            setColors();

            var normalBuffer = gl.createBuffer();
            gl.bindBuffer(gl.ARRAY_BUFFER, normalBuffer);
            setNormal();

            //drawScene
            drawScene();


            //绘制
            function drawScene(){
                webglUtils.resizeCanvasToDisplaySize(gl.canvas);
                gl.viewport(0, 0, gl.canvas.width, gl.canvas.height);

                gl.clearColor(0.0, 0.0, 0.0, 1.0);
                gl.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT);

                gl.enable(gl.CULL_FACE);//剔除成遮挡面
                gl.enable(gl.DEPTH_TEST);//深度缓冲区

                gl.useProgram(program);

                gl.enableVertexAttribArray(a_Position);
                gl.bindBuffer(gl.ARRAY_BUFFER, vertexBuffer);
                gl.vertexAttribPointer(a_Position, 3, gl.FLOAT, false,  0, 0);
                // gl.enableVertexAttribArray(a_Color);
                // gl.bindBuffer(gl.ARRAY_BUFFER, colorBuffer);
                // gl.vertexAttribPointer(a_Color, 3, gl.UNSIGNED_BYTE, true,  0, 0); //normlize => 0至255标准化为 0-1
                gl.uniform4fv(u_Color, [0.2, 1, 0.2, 1]);
                gl.enableVertexAttribArray(a_Normal);
                gl.bindBuffer(gl.ARRAY_BUFFER, normalBuffer);
                gl.vertexAttribPointer(a_Normal, 3, gl.FLOAT, false,  0, 0);
                gl.uniform3fv(u_ReverseLightDirection, m4.normalize([0.5, 0.7, 1]));


                //投影
                //var projectionMatrix = m4.orthographic(0, gl.canvas.width, gl.canvas.height, 0, 400, -400);
                var projectionMatrix = m4.perspective(degToRad(60), gl.canvas.width / gl.canvas.height, 1, 2000);//fieldOfViewInRadians, aspect, near, far
                
                //View
                var cameraPosition = [100, 150, 200];
                var cameraTarget = [0, 35, 0];
                var up = [0, 1, 0];
                var cameramMatrix = m4.lookAt(cameraPosition, cameraTarget, up);
                var viewMatrix = m4.inverse(cameramMatrix);

                var viewProjectionMatrix = m4.multiply(projectionMatrix, viewMatrix);

                var worldMatrix = m4.translation(0, 100, 0);
                worldMatrix = m4.xRotate(worldMatrix, Math.PI);
                worldMatrix = m4.yRotate(worldMatrix, fRotationRadians);

                var worldViewProjection = m4.multiply(viewProjectionMatrix, worldMatrix);
                gl.uniformMatrix4fv(u_WorldViewProjection, false, worldViewProjection);

                worldMatrix = m4.inverse(worldMatrix);
                worldMatrix = m4.transpose(worldMatrix);
                gl.uniformMatrix4fv(u_World, false, worldMatrix);

                gl.drawArrays(gl.TRIANGLES, 0, 6 * 16);
            }

            function setupUI(){
                webglUtils.resizeCanvasToDisplaySize(gl.canvas);
                //webglLessonsUI.setupSlider("#cx", {value: cameraTarget[0], slide: updateCamera(0), max: gl.canvas.width });
                webglLessonsUI.setupSlider("#angleY", {value: radToDeg(fRotationRadians), slide: updateRotation, min: -360, max: 360 });
            }

            function updateCamera(index) {
                return function(event, ui){
                    cameraTarget[index] = ui.value;
                    drawScene();
                }
            }

            function updateRotation(event, ui){
                fRotationRadians = degToRad(ui.value);
                drawScene();
            }

            //顶点属性
            function setRectangle(){
                var positions = new Float32Array([
                    // left column front
                    0,   0,  0,
                    0, 150,  0,
                    30,   0,  0,
                    0, 150,  0,
                    30, 150,  0,
                    30,   0,  0,

                    // top rung front
                    30,   0,  0,
                    30,  30,  0,
                    100,   0,  0,
                    30,  30,  0,
                    100,  30,  0,
                    100,   0,  0,

                    // middle rung front
                    30,  60,  0,
                    30,  90,  0,
                    67,  60,  0,
                    30,  90,  0,
                    67,  90,  0,
                    67,  60,  0,

                    // left column back
                        0,   0,  30,
                    30,   0,  30,
                        0, 150,  30,
                        0, 150,  30,
                    30,   0,  30,
                    30, 150,  30,

                    // top rung back
                    30,   0,  30,
                    100,   0,  30,
                    30,  30,  30,
                    30,  30,  30,
                    100,   0,  30,
                    100,  30,  30,

                    // middle rung back
                    30,  60,  30,
                    67,  60,  30,
                    30,  90,  30,
                    30,  90,  30,
                    67,  60,  30,
                    67,  90,  30,

                    // top
                        0,   0,   0,
                    100,   0,   0,
                    100,   0,  30,
                        0,   0,   0,
                    100,   0,  30,
                        0,   0,  30,

                    // top rung right
                    100,   0,   0,
                    100,  30,   0,
                    100,  30,  30,
                    100,   0,   0,
                    100,  30,  30,
                    100,   0,  30,

                    // under top rung
                    30,   30,   0,
                    30,   30,  30,
                    100,  30,  30,
                    30,   30,   0,
                    100,  30,  30,
                    100,  30,   0,

                    // between top rung and middle
                    30,   30,   0,
                    30,   60,  30,
                    30,   30,  30,
                    30,   30,   0,
                    30,   60,   0,
                    30,   60,  30,

                    // top of middle rung
                    30,   60,   0,
                    67,   60,  30,
                    30,   60,  30,
                    30,   60,   0,
                    67,   60,   0,
                    67,   60,  30,

                    // right of middle rung
                    67,   60,   0,
                    67,   90,  30,
                    67,   60,  30,
                    67,   60,   0,
                    67,   90,   0,
                    67,   90,  30,

                    // bottom of middle rung.
                    30,   90,   0,
                    30,   90,  30,
                    67,   90,  30,
                    30,   90,   0,
                    67,   90,  30,
                    67,   90,   0,

                    // right of bottom
                    30,   90,   0,
                    30,  150,  30,
                    30,   90,  30,
                    30,   90,   0,
                    30,  150,   0,
                    30,  150,  30,

                    // bottom
                    0,   150,   0,
                    0,   150,  30,
                    30,  150,  30,
                    0,   150,   0,
                    30,  150,  30,
                    30,  150,   0,

                    // left side
                    0,   0,   0,
                    0,   0,  30,
                    0, 150,  30,
                    0,   0,   0,
                    0, 150,  30,
                    0, 150,   0
                ]);

                gl.bufferData(gl.ARRAY_BUFFER, positions, gl.STATIC_DRAW);
            }

            function setColors(){
                gl.bufferData(gl.ARRAY_BUFFER, new Uint8Array([
                        // left column front
                        200,  70, 120,
                        200,  70, 120,
                        200,  70, 120,
                        200,  70, 120,
                        200,  70, 120,
                        200,  70, 120,

                        // top rung front
                        200,  70, 120,
                        200,  70, 120,
                        200,  70, 120,
                        200,  70, 120,
                        200,  70, 120,
                        200,  70, 120,

                        // middle rung front
                        200,  70, 120,
                        200,  70, 120,
                        200,  70, 120,
                        200,  70, 120,
                        200,  70, 120,
                        200,  70, 120,

                        // left column back
                        80, 70, 200,
                        80, 70, 200,
                        80, 70, 200,
                        80, 70, 200,
                        80, 70, 200,
                        80, 70, 200,

                        // top rung back
                        80, 70, 200,
                        80, 70, 200,
                        80, 70, 200,
                        80, 70, 200,
                        80, 70, 200,
                        80, 70, 200,

                        // middle rung back
                        80, 70, 200,
                        80, 70, 200,
                        80, 70, 200,
                        80, 70, 200,
                        80, 70, 200,
                        80, 70, 200,

                        // top
                        70, 200, 210,
                        70, 200, 210,
                        70, 200, 210,
                        70, 200, 210,
                        70, 200, 210,
                        70, 200, 210,

                        // top rung right
                        200, 200, 70,
                        200, 200, 70,
                        200, 200, 70,
                        200, 200, 70,
                        200, 200, 70,
                        200, 200, 70,

                        // under top rung
                        210, 100, 70,
                        210, 100, 70,
                        210, 100, 70,
                        210, 100, 70,
                        210, 100, 70,
                        210, 100, 70,

                        // between top rung and middle
                        210, 160, 70,
                        210, 160, 70,
                        210, 160, 70,
                        210, 160, 70,
                        210, 160, 70,
                        210, 160, 70,

                        // top of middle rung
                        70, 180, 210,
                        70, 180, 210,
                        70, 180, 210,
                        70, 180, 210,
                        70, 180, 210,
                        70, 180, 210,

                        // right of middle rung
                        100, 70, 210,
                        100, 70, 210,
                        100, 70, 210,
                        100, 70, 210,
                        100, 70, 210,
                        100, 70, 210,

                        // bottom of middle rung.
                        76, 210, 100,
                        76, 210, 100,
                        76, 210, 100,
                        76, 210, 100,
                        76, 210, 100,
                        76, 210, 100,

                        // right of bottom
                        140, 210, 80,
                        140, 210, 80,
                        140, 210, 80,
                        140, 210, 80,
                        140, 210, 80,
                        140, 210, 80,

                        // bottom
                        90, 130, 110,
                        90, 130, 110,
                        90, 130, 110,
                        90, 130, 110,
                        90, 130, 110,
                        90, 130, 110,

                        // left side
                        160, 160, 220,
                        160, 160, 220,
                        160, 160, 220,
                        160, 160, 220,
                        160, 160, 220,
                        160, 160, 220
                ]), gl.STATIC_DRAW)
            }
            
            function setNormal(){
                var normals = new Float32Array([
                    // 正面左竖
                    0, 0, 1,
                    0, 0, 1,
                    0, 0, 1,
                    0, 0, 1,
                    0, 0, 1,
                    0, 0, 1,
            
                    // 正面上横
                    0, 0, 1,
                    0, 0, 1,
                    0, 0, 1,
                    0, 0, 1,
                    0, 0, 1,
                    0, 0, 1,
            
                    // 正面中横
                    0, 0, 1,
                    0, 0, 1,
                    0, 0, 1,
                    0, 0, 1,
                    0, 0, 1,
                    0, 0, 1,
            
                    // 背面左竖
                    0, 0, -1,
                    0, 0, -1,
                    0, 0, -1,
                    0, 0, -1,
                    0, 0, -1,
                    0, 0, -1,
            
                    // 背面上横
                    0, 0, -1,
                    0, 0, -1,
                    0, 0, -1,
                    0, 0, -1,
                    0, 0, -1,
                    0, 0, -1,
            
                    // 背面中横
                    0, 0, -1,
                    0, 0, -1,
                    0, 0, -1,
                    0, 0, -1,
                    0, 0, -1,
                    0, 0, -1,
            
                    // 顶部
                    0, 1, 0,
                    0, 1, 0,
                    0, 1, 0,
                    0, 1, 0,
                    0, 1, 0,
                    0, 1, 0,
            
                    // 上横右面
                    1, 0, 0,
                    1, 0, 0,
                    1, 0, 0,
                    1, 0, 0,
                    1, 0, 0,
                    1, 0, 0,
            
                    // 上横下面
                    0, -1, 0,
                    0, -1, 0,
                    0, -1, 0,
                    0, -1, 0,
                    0, -1, 0,
                    0, -1, 0,
            
                    // 上横和中横之间
                    1, 0, 0,
                    1, 0, 0,
                    1, 0, 0,
                    1, 0, 0,
                    1, 0, 0,
                    1, 0, 0,
            
                    // 中横上面
                    0, 1, 0,
                    0, 1, 0,
                    0, 1, 0,
                    0, 1, 0,
                    0, 1, 0,
                    0, 1, 0,
            
                    // 中横右面
                    1, 0, 0,
                    1, 0, 0,
                    1, 0, 0,
                    1, 0, 0,
                    1, 0, 0,
                    1, 0, 0,
            
                    // 中横底面
                    0, -1, 0,
                    0, -1, 0,
                    0, -1, 0,
                    0, -1, 0,
                    0, -1, 0,
                    0, -1, 0,
            
                    // 底部右侧
                    1, 0, 0,
                    1, 0, 0,
                    1, 0, 0,
                    1, 0, 0,
                    1, 0, 0,
                    1, 0, 0,
            
                    // 底面
                    0, -1, 0,
                    0, -1, 0,
                    0, -1, 0,
                    0, -1, 0,
                    0, -1, 0,
                    0, -1, 0,
            
                    // 左面
                    -1, 0, 0,
                    -1, 0, 0,
                    -1, 0, 0,
                    -1, 0, 0,
                    -1, 0, 0,
                    -1, 0, 0]);
                gl.bufferData(gl.ARRAY_BUFFER, normals, gl.STATIC_DRAW);
            }
        }

        function degToRad(d){
            return d * Math.PI / 180;
        }

        function radToDeg (r) {
            return r * 180 / Math.PI;
        }
    </script>
</html>